<?php

defined('SYSPATH') or die('Access error!');

/**
 * html helper类 
 */
class HTML
{

    /**
     * @var  array  属性的顺序
     */
    public static $attribute_order = array
        (
        'action',
        'method',
        'type',
        'id',
        'name',
        'value',
        'href',
        'src',
        'width',
        'height',
        'cols',
        'rows',
        'size',
        'maxlength',
        'rel',
        'media',
        'accept-charset',
        'accept',
        'tabindex',
        'accesskey',
        'alt',
        'title',
        'class',
        'style',
        'selected',
        'checked',
        'readonly',
        'disabled',
    );
    public static $allowed_elements_arr = array('<p>', '<strong>', '<em>', '<u>', '<h1>', '<h2>', '<h3>', '<h4>', '<h5>', '<h6>', '<img>', '<li>', '<ol>', '<ul>', '<span>', '<div>', '<br>', '<br/>', '<br />', '<ins>', '<del>', '<address>', '<hr>', '<hr/>', '<hr />', '<blockquote>');
    public static  $allowed_elements = '';

    /**
     * @var  boolean  是否另起新的页面?
     */
    public static $windowed_urls = FALSE;

    /**
     * 初始化内容操作
     * @param type $content
     * @return type 
     */
     public static function sanitize_content($content, $allowd_elemets = '')
    {
        if (!isset($content))
            return;

        $content = HTML::strip_tags_attributes($content);

        $content = HTML::get_safe_content($content, $allowd_elemets);

        return $content;
    }

    /**
     * 获取需要的安全数据
     * 
     * @return string
     */
     public static function get_safe_content($content, $allowd_elemets = '')
    {
        HTML::$allowed_elements = implode(HTML::$allowed_elements_arr);
        if ($allowd_elemets != '')
        {
            HTML::$allowed_elements = implode($allowd_elemets);
        }
        return strip_tags(stripslashes($content), HTML::$allowed_elements);
    }

    /**
     *  过滤不安全的javascript操作
     * @param type $source_text
     * @param string $banned_attributes
     * @return type 
     */
    private static function strip_tags_attributes($source_text, $banned_attributes = array())
    {
        if (empty($banned_attributes))
            $banned_attributes = array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavaible', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragdrop', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterupdate', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmoveout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload');

        return preg_replace('/<(.*?)>/ie', "'<' . preg_replace(array('/javascript:[^\"\']*/i', '/(" . implode('|', $banned_attributes) . ")[ \\t\\n]*=[ \\t\\n]*[\"\'][^\"\']*[\"\']/i', '/\s+/'), array('', '', ' '), stripslashes('\\1')) . '>'", strip_tags($source_text, implode('', HTML::$allowed_elements_arr)));
    }

    /**
     * 转换个别html标签为实体 防止XSS攻击
     *   '&' (ampersand) becomes '&amp;'
     *   '"' (double quote) becomes '&quot;' 
     *   ''' (single quote) becomes '&#039;' 
     *   '<' (less than) becomes '&lt;'
     *   '>' (greater than) becomes '&gt;'
     *
     *     echo HTML::chars($username);
     *
     * @return  string
     */
    public static function chars($value, $double_encode = TRUE)
    {
        return htmlspecialchars((string) $value, ENT_QUOTES, Core::$charset, $double_encode);
    }

    /**
     * 转换所有的html标签为实体 
     *
     *     echo HTML::entities($username);
     *
     * @param   string   string to convert
     * @param   boolean  encode existing entities
     * @return  string
     */
    public static function entities($value, $double_encode = TRUE)
    {
        return htmlentities((string) $value, ENT_QUOTES, Core::$charset, $double_encode);
    }

    /**
     *  去除html中不规则内容字符
     * @access    public
     * @param     string  $str  需要处理的字符串
     * @param     string  $rptype  返回类型
     *            $rptype = 0 表示仅替换 html标记
     *            $rptype = 1 表示替换 html标记同时去除连续空白字符
     *            $rptype = 2 表示替换 html标记同时去除所有空白字符
     *            $rptype = 3 表示替换 html危险的标记并且取出html标记
     *            $rptype = -1 表示仅替换 html危险的标记 
     * @return    string
     */
    public static function cut_bad_code($str, $rptype = 0)
    {
        $str = stripslashes($str);
        if ($rptype == 0)
        {
            $str = htmlspecialchars($str);
        }
        else if ($rptype == 1)
        {
            $str = htmlspecialchars($str);
            $str = str_replace("　", ' ', $str);
            $str = preg_replace("/[\r\n\t ]{1,}/", ' ', $str);
        }
        else if ($rptype == 2)
        {
            $str = htmlspecialchars($str);
            $str = str_replace("　", '', $str);
            $str = preg_replace("/[\r\n\t ]/", '', $str);
        }
        elseif ($rptype == 3)
        {
            $str = preg_replace("/[\r\n\t ]{1,}/", ' ', $str);
            $str = preg_replace('/script/i', 'ｓｃｒｉｐｔ', $str);
            $str = preg_replace("/<[\/]{0,1}(link|meta|ifr|fra)[^>]*>/i", '', $str);
            $str = htmlspecialchars($str);
        }
        else
        {
            $str = preg_replace("/[\r\n\t ]{1,}/", ' ', $str);
            $str = preg_replace('/script/i', 'ｓｃｒｉｐｔ', $str);
            $str = preg_replace("/<[\/]{0,1}(link|meta|ifr|fra)[^>]*>/i", '', $str);
        }
        return addslashes($str);
    }

    /**
     * 生成一个a标签的文字链接
     *
     *     echo HTML::anchor('/user/profile', 'My Profile');
     *
     * @param   string  链接地址
     * @param   string  链接文字
     * @param   array   a标签的属性
     * @param   string  特殊的一些协议
     * @return  string
     * @uses    URL::base
     * @uses    URL::site
     * @uses    HTML::attributes
     */
    public static function anchor($uri, $title = NULL, array $attributes = NULL, $protocol = NULL)
    {
        if ($title === NULL)
        {
            $title = $uri;
        }

        if ($uri === '')
        {
            $uri = URL::base(FALSE, $protocol);
        }
        else
        {
            if (strpos($uri, '://') !== FALSE)
            {
                if (HTML::$windowed_urls === TRUE AND empty($attributes['target']))
                {
                    $attributes['target'] = '_blank';
                }
            }
            elseif ($uri[0] !== '#')
            {
                $uri = URL::site($uri, $protocol);
            }
        }

        $attributes['href'] = $uri;

        return '<a' . HTML::attributes($attributes) . '>' . $title . '</a>';
    }

    /**
     *  给某个文字生成一个文件的链接 例如图片 文档下载
     *
     *     echo HTML::file_anchor('media/doc/user_guide.pdf', 'User Guide');
     *
     * @param   string  文件的地址
     * @param   string  链接的文字
     * @param   array  链接的属性
     * @param   string  协议 例如: ftp
     * @return  string
     * @uses    URL::base
     * @uses    HTML::attributes
     */
    public static function file_anchor($file, $title = NULL, array $attributes = NULL, $protocol = NULL)
    {
        if ($title === NULL)
        {
            $title = basename($file);
        }

        $attributes['href'] = URL::base(FALSE, $protocol) . $file;

        return '<a' . HTML::attributes($attributes) . '>' . $title . '</a>';
    }

    /**
     *  生成一个模糊的字符串可以防止机器人和垃圾邮件
     *
     *     echo HTML::obfuscate($text);
     *
     * @param   string  需要被处理的字符串
     * @return  string
     * @since   3.0.3
     */
    public static function obfuscate($string)
    {
        $safe = '';
        foreach (str_split($string) as $letter)
        {
            switch (rand(1, 3))
            {
                case 1:
                    $safe .= '&#' . ord($letter) . ';';
                    break;

                case 2:
                    $safe .= '&#x' . dechex(ord($letter)) . ';';
                    break;

                case 3:
                    $safe .= $letter;
            }
        }

        return $safe;
    }

    /**
     *  把合法的邮件给模糊化，防止垃圾邮件
     *
     *     echo HTML::email($address);
     *
     * @param   string  email 
     * @return  string
     * @uses    HTML::obfuscate
     */
    public static function email($email)
    {
        return str_replace('@', '&#64;', HTML::obfuscate($email));
    }

    /**
     * 生成一个邮件链接
     *
     *     echo HTML::mailto($address);
     *
     * @param   string  email地址
     * @param   string  显示的文字
     * @param   array  需要的属性
     * @return  string
     * @uses    HTML::email
     * @uses    HTML::attributes
     */
    public static function mailto($email, $title = NULL, array $attributes = NULL)
    {
        $email = HTML::email($email);

        if ($title === NULL)
        {
            $title = $email;
        }

        return '<a href="&#109;&#097;&#105;&#108;&#116;&#111;&#058;' . $email . '"' . HTML::attributes($attributes) . '>' . $title . '</a>';
    }

    /**
     * 生成一个css的链接
     *
     *     echo HTML::style('media/css/screen.css');
     *
     * @param   string  文件的地址
     * @param   array   属性
     * @param   boolean  首页地址表示
     * @return  string
     * @uses    URL::base
     * @uses    HTML::attributes
     */
    public static function style($file, array $attributes = NULL, $index = FALSE)
    {
        if (strpos($file, '://') === FALSE)
        {
            $file = URL::base($index) . $file;
        }

        $attributes['href'] = $file;

        $attributes['rel'] = 'stylesheet';

        $attributes['type'] = 'text/css';

        return '<link' . HTML::attributes($attributes) . ' />';
    }

    /**
     * 生成一个js的链接
     *
     *     echo HTML::script('media/js/jquery.min.js');
     *
     * @param   string  文件的地址
     * @param   array   属性
     * @param   boolean  首页地址表示
     * @return  string
     * @uses    URL::base
     * @uses    HTML::attributes
     */
    public static function script($file, array $attributes = NULL, $index = FALSE)
    {
        if (strpos($file, '://') === FALSE)
        {
            $file = URL::base($index) . $file;
        }

        $attributes['src'] = $file;

        $attributes['type'] = 'text/javascript';

        return '<script' . HTML::attributes($attributes) . '></script>';
    }

    /**
     * 生成一个图片的链接
     *
     *     echo HTML::image('media/img/logo.png', array('alt' => '网站logo'));
     *
     * @param   string   图片地址
     * @param   array    图片需要的属性
     * @return  string
     * @uses    URL::base
     * @uses    HTML::attributes
     */
    public static function image($file, array $attributes = NULL, $index = FALSE)
    {
        if (strpos($file, '://') === FALSE)
        {
            $file = URL::base($index) . $file;
        }

        $attributes['src'] = $file;

        return '<img' . HTML::attributes($attributes) . ' />';
    }

    /**
     * 处理html 所需要的属性
     *
     *     echo '<div'.HTML::attributes($attrs).'>'.$content.'</div>';
     *
     * @param   array   属性列表
     * @return  string
     */
    public static function attributes(array $attributes = NULL)
    {
        if (empty($attributes))
            return '';

        $sorted = array();
        foreach (HTML::$attribute_order as $key)
        {
            if (isset($attributes[$key]))
            {
                $sorted[$key] = $attributes[$key];
            }
        }

        $attributes = $sorted + $attributes;

        $compiled = '';
        foreach ($attributes as $key => $value)
        {
            if ($value === NULL)
            {
                continue;
            }

            if (is_int($key))
            {
                $key = $value;
            }

            $compiled .= ' ' . $key . '="' . HTML::chars($value) . '"';
        }

        return $compiled;
    }

}
